/********************************************************************************
 * @file    bsp_io.h
 * @author  jianqiang.xue
 * @version V2.0.0
 * @date    2023-07-10
 * @brief   IO控制
 ********************************************************************************/

#ifndef __BSP_IO_H
#define __BSP_IO_H

/* Includes ------------------------------------------------------------------*/
#include <stdbool.h>
#include <stdint.h>

/* Public Enum ---------------------------------------------------------------*/
/**
 * @brief  GPIO Bit SET and Bit RESET enumeration
 */
typedef enum {
    IO_LOW = 0U,   // 低电平
    IO_HIGH,       // 高电平
    IO_VALID,      // 有效电平 (仅设置电平有效，电平取决于io.level)
    IO_NOVALID,    // 无效电平 (仅设置电平有效，电平取决于io.level)
} io_ste_t;

typedef enum {
    IO_NOPULL = 0U, // 无上下拉
    IO_PULLUP,      // 上拉
    IO_PULLDOWN     // 下拉
} io_pull_t;

typedef enum {
    IO_OUT_OD = 0U,     // 开漏输出
    IO_OUT_PP,          // 推免输出
    IO_OUT_AF_OD,       // 复用开漏输出
    IO_OUT_AF_PP        // 复用推免输出
} io_out_t;

typedef enum {
    IO_EXTI_LEVEL = 0U,  // 电平触发
    IO_EXTI_EDGE,        // 边沿触发
} io_exti_t;

typedef enum {
    IO_EXTI_EVENT_LOWFALL = 0U,  // 低电平触发(下降沿)
    IO_EXTI_EVENT_HIGHRISE,      // 高电平触发(上降沿)
    IO_EXTI_EVENT_FALLRISE       // 高低电平触发或任意电平变化
} io_exti_event_t;

typedef struct { // 常用引脚配置
    void* port;       // 端点号
    uint8_t pin;      // 引脚号
    uint32_t periph;  // GPIO外设时钟 比如 RCC_APB2PERIPH_GPIOA
    uint8_t irqn;     // 中断号 比如 EXT0_IRQn
    uint8_t level;    // 电平有效状态，比如低电平点亮led，则level设置0，反之。
} bsp_gpio_t;

typedef struct { // 用于外设引脚初始化(简化)
    void* port;       // 端点号
    uint8_t pin;      // 引脚号
    uint32_t periph;  // GPIO外设时钟 比如 RCC_APB2PERIPH_GPIOA
} bsp_gpio2_t;
/* Public Function Prototypes ------------------------------------------------*/

// 常规引脚初始化

void io_deinit(uint8_t io);
void io_set_out_mode(uint8_t io, io_out_t out_mode);
void io_set_in_mode(uint8_t io, io_pull_t pull);

void io_set_exit_in(uint8_t io, io_exti_t exti_type,
                        io_exti_event_t exti_event, io_pull_t pull);

// 引脚控制和状态获取

void io_out(uint8_t io, io_ste_t state);
void io_toggle(uint8_t io);
bool get_io_ste(uint8_t io);

#endif
